//////////////////////////////////////////////
// Environment.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Forward decl -----------------------------

namespace nkScripts
{
	class EnvironmentStrategy ;
	class Function ;
	class Namespace ;
	class Script ;
	class ScriptObjectReference ;
	class UserType ;

	enum class INTERPRETER ;

	struct ExecutionResult ;
}

/// Includes ---------------------------------

// nkScripts
#include "../Dll/DllDefines.h"

#include "Functions/FunctionDefines.h"

// nkMemory
#include <NilkinsMemory/Containers/Buffer.h>
#include <NilkinsMemory/Containers/BufferView.h>
#include <NilkinsMemory/Containers/StringView.h>

// Standards
#include <string>
#include <unordered_map>

/// Class ------------------------------------

namespace nkScripts
{
	class DLL_SCRIPTS_EXPORT Environment NK_FINAL
	{
		public :

			// Destructor
			NK_FORCE_EXPORT_CALL ~Environment () ;

			// Getters
			const ExecutionResult& getLastExecutionResult () const ;
			nkMemory::StringView getName () const ;

			// Setters
			void setEnvironmentFor (INTERPRETER interpretType) ;
			void setName (nkMemory::StringView name) ;

			// Exécution
			bool execute (const Script& script) ;
			void requestGarbageCollection () ;

			// Manipulation mémoire environnement
			void setVar (nkMemory::StringView name, bool value) ;
			void setVar (nkMemory::StringView name, int value) ;
			void setVar (nkMemory::StringView name, float value) ;
			void setVar (nkMemory::StringView name, double value) ;
			void setVar (nkMemory::StringView name, const char* value) ;
			void setVar (nkMemory::StringView name, nkMemory::StringView value) ;
			void setVar (nkMemory::StringView name, const ScriptObjectReference& value) ;
			void setObject (nkMemory::StringView name, nkMemory::StringView userTypeName, void* value) ;

			bool isVarSet (nkMemory::StringView name) ;

			bool getVar (nkMemory::StringView name, bool defaultValue) ;
			int getVar (nkMemory::StringView name, int defaultValue) ;
			float getVar (nkMemory::StringView name, float defaultValue) ;
			double getVar (nkMemory::StringView name, double defaultValue) ;
			nkMemory::StringView getVar (nkMemory::StringView name, const char* defaultValue) ;
			nkMemory::StringView getVar (nkMemory::StringView name, nkMemory::StringView defaultValue) ;
			ScriptObjectReference getVar (nkMemory::StringView name) ;
			void* getObject (nkMemory::StringView name, nkMemory::StringView userTypeName = nullptr) ;
			ScriptObjectReference getScriptFunction (nkMemory::StringView name) ;

			// Ajout de fonctions
			Function* setFunc (nkMemory::StringView name) ;
			bool isFuncSet (nkMemory::StringView name) ;
			Function* getFunc (nkMemory::StringView name) ;

			// Ajout de types persos
			UserType* setUserType (nkMemory::StringView name) ;
			bool isUserTypeSet (nkMemory::StringView name) ;
			UserType* getUserType (nkMemory::StringView name) ;

			// Ajout de namespaces
			Namespace* setNamespace (nkMemory::StringView name) ;
			bool isNamespaceSet (nkMemory::StringView name) ;
			Namespace* getNamespace (nkMemory::StringView name) ;

			// Call C++ -> Script
			bool callScriptFunction (const ScriptObjectReference& reference, const DataStack& args, DataStack& expectedOutput) ;
			nkMemory::Buffer serializeScriptObject (const ScriptObjectReference& reference, bool forwardUserDataOwnership = false) ;
			ScriptObjectReference deserializeScriptObject (nkMemory::BufferView<unsigned char> object) ;

		public :

			public :

			// Statics
			static nkMemory::UniquePtr<Environment> create () noexcept ;
			static nkMemory::UniquePtr<Environment> create (Environment&& other) noexcept ;

		private :

			// Constructors
			Environment () noexcept ;
			Environment (const Environment&) noexcept = delete ;
			Environment (Environment&&) noexcept ;

		private :

			// Attributes
			// Name de l'environment
			nkMemory::String _name ;
			// List des fonctions actives
			std::unordered_map<std::string, Function*> _activeFunctions ;
			// Et des types actifs
			std::unordered_map<std::string, UserType*> _activeTypes ;
			// Namespaces actifs
			std::unordered_map<std::string, Namespace*> _activeNamespaces ;

			// L'environnement interne
			EnvironmentStrategy* _env ;

			// Interpreter Type actuel
			INTERPRETER _interpreterType ;
	} ;
}

